#!/usr/bin/env python
# encoding: utf-8
"""
snowball_ob.py

Created by Bud Gibson on 2010-07-20.
Copyright (c) 2010 Bud Gibson. Available under the GPL/Artistic License.
"""

import datetime
import simplejson as json
from config import conf
from db_setup import db, btree
from NetworkNode import NetworkNode
from buzztracker.exceptions import HttpError as HttpError


try:
  from buzztracker.analytics.group_compare import group_in_out_labeled,\
    group_non_reciprocator, group_intersection, set_of_ids
  #from buzztracker.utilities.sorters import sort_displayName
  from buzztracker.REST.poco_public import list_profile_stubs, followers_of,\
    followed_by
  from buzztracker import conf
  from buzztracker.persistnet.dbo import DataBase
  from buzztracker.persistnet.dbo import transaction
except ImportError:
  print 'buzztracker is not on your system path'
  raise

def sort_displayName(x,y):
  """sort a list of profiles or profile stubs by display name"""
  return(cmp(x.displayName.lower(),y.displayName.lower()))
    
def append_nodes(nodes=[], depth=0, btree=btree):
  """Add persistent nodes to the database"""
  for node in nodes:
    if node['id'] not in btree:
      node['depth'] = 0
      node = NetworkNode(node)
      btree[node.id] = node
      transaction.commit()
      
def get_persistent(node, depth=0, node_obj=NetworkNode, btree=btree):
  """Returns a persisted node"""
  try:
    return btree[node['id']]
  except KeyError:
    node['depth'] = depth
    btree[node['id']] = node_obj(node)
    return btree[node['id']]

def augment_nodes(node_ids, btree=btree):
  """compute symmetric followers"""
  for node_id in node_ids:
    node = btree[node_id]
    if node.public == 'unknown':
      try:
        followers = followers_of(node.id)
      except json.decoder.JSONDecodeError as jde:
        node.public = 'exception'
        node.exceptionMSG = jde.msg + str(jde.pos)
        node.exceptionDOC = jde.doc
        transaction.commit()
        print '*' * 80
        print node.id, node.displayName, 'followers', 'JSONDecodeError'
        print jde.msg, jde.pos
        print '*' * 80
        continue
      except HttpError as fe:
        node.public = 'exception'
        node.exceptionMSG = str(fe)
        transaction.commit()
        print '*' * 80
        print fe
        print '*' * 80
        continue
      try:
        following = followed_by(node.id)
      except json.decoder.JSONDecodeError as jde:
        node.public = 'exception'
        node.exceptionMSG = jde.msg + str(jde.pos)
        node.exceptionDOC = jde.doc
        transaction.commit()
        print '*' * 80
        print node.id, node.displayName, 'following', 'JSONDecodeError'
        print jde.msg, jde.pos
        print '*' * 80
        continue
      except HttpError as fe:
        node.public = 'exception'
        node.exceptionMSG = str(fe)
        transaction.commit()
        print '*' * 80
        print fe
        print '*' * 80
        continue      
      if followers or following:
        node.public = True
      else:
        node.public = False
      if node.public:
        syms = group_intersection(following,followers)
        for sym in syms:
          sym = get_persistent(sym,node.depth+1)
          node.add_tie(sym)
          sym.add_net_tie(node)
        transaction.commit()

def snowballer(max_depth=0, btree=btree, db=db):
  """Do a snowball sample out to the specified depth"""
  if len(btree) == 0:
    seed_nodes = list_profile_stubs(conf.SEED)
    for node in seed_nodes:
      get_persistent(node)
  while True:
    update_ids = [v.id for v in btree.values() 
                  if v.depth <= max_depth and v.public == 'unknown']
    if update_ids:
      augment_nodes(update_ids)
      db.pack()
    else:
      break
            
def summarize_network(btree=btree):
  """docstring for summarize_network"""
  for node in sorted(btree.values(),sort_displayName):
    if node.public != 'unknown':
      print node.displayName, node.depth, node.public, node.count_ties, node.count_net_ties, node.reach

def main():  
  snowballer(1)
  summarize_network()
  


if __name__ == '__main__':
  main()

